/*
	https://github.com/Norkart/Leaflet-MiniMap
	
*/

L.Control.MiniMap = L.Control.extend({
    options: {
        position: 'bottomright',
        toggleDisplay: false,
        zoomLevelOffset: -5,
        zoomLevelFixed: false,
        zoomAnimation: false,
        autoToggleDisplay: false,
		show_view: true,
        width: 150,
        height: 150,
        aimingRectOptions: {
            color: "#c34528",
            weight: 1,
            clickable: false,
			stroke:true
        },
        shadowRectOptions: {
            color: "#000000",
            weight: 1,
            clickable: false,
            opacity: 0,
            fillOpacity: 0
        }
    },

    hideText: 'Hide MiniMap',

    showText: 'Show MiniMap',

    //layer is the map layer to be shown in the minimap
    initialize: function(layer, options) {
        L.Util.setOptions(this, options);
        //Make sure the aiming rects are non-clickable even if the user tries to set them clickable (most likely by forgetting to specify them false)
        this.options.aimingRectOptions.clickable = false;
        this.options.shadowRectOptions.clickable = false;
        this._layer = layer;
    },

    onAdd: function(map) {

        this._mainMap = map;

        //Creating the container and stopping events from spilling through to the main map.
        this._container = L.DomUtil.create('div', 'leaflet-control-minimap');
        this._container.style.width = this.options.width + 'px';
        this._container.style.height = this.options.height + 'px';
        L.DomEvent.disableClickPropagation(this._container);
        L.DomEvent.on(this._container, 'mousewheel', L.DomEvent.stopPropagation);


        this._miniMap = new L.Map(this._container, {
            attributionControl: false,
            zoomControl: false,
            zoomAnimation: this.options.zoomAnimation,
            autoToggleDisplay: this.options.autoToggleDisplay,
            touchZoom: false,
            scrollWheelZoom: false,
            doubleClickZoom: false,
            boxZoom: false,
			dragging:false,
            crs: map.options.crs
        });

        this._miniMap.addLayer(this._layer);

        //These bools are used to prevent infinite loops of the two maps notifying each other that they've moved.
        this._mainMapMoving = false;
        this._miniMapMoving = false;

        //Keep a record of this to prevent auto toggling when the user explicitly doesn't want it.
        this._userToggledDisplay = false;
        this._minimized = false;

        if (this.options.toggleDisplay) {
            this._addToggleButton();
        }

        this._miniMap.whenReady(L.Util.bind(function() {
            this._aimingRect = L.rectangle(this._mainMap.getBounds(), this.options.aimingRectOptions).addTo(this._miniMap);
            this._shadowRect = L.rectangle(this._mainMap.getBounds(), this.options.shadowRectOptions).addTo(this._miniMap);
			
			this._locationCircle = L.circleMarker(this._mainMap.getCenter(), {
				fillColor: "#c34528",
				color: "#FFFFFF",
				weight:2,
				radius: 10,
				fill:true,
				fillOpacity: 1,
				stroke:true,
				clickable: false
			}).addTo(this._miniMap);
			this._locationCircle.setRadius(5);
			
            this._mainMap.on('moveend', this._onMainMapMoved, this);
            this._mainMap.on('move', this._onMainMapMoving, this);
            //this._miniMap.on('movestart', this._onMiniMapMoveStarted, this);
            //this._miniMap.on('move', this._onMiniMapMoving, this);
            //this._miniMap.on('moveend', this._onMiniMapMoved, this);
			if (this.options.bounds_array) {
				this._miniMap.fitBounds(this.options.bounds_array, {padding:[15,15]});
			}
        }, this));

        return this._container;
    },
	
	minimize: function(hide_completely) {
		if (!this._minimized) {
			this._minimize();
		}
	},
	
	restore: function() {
		if (this._minimized) {
			this._restore();
			this._miniMap.fitBounds(this.options.bounds_array, {padding:[15,15]});
		}
	},

    addTo: function(map) {
        L.Control.prototype.addTo.call(this, map);
        this._miniMap.setView(this._mainMap.getCenter(), this._decideZoom(true));
        this._setDisplay(this._decideMinimized());
        return this;
    },

    onRemove: function(map) {
        this._mainMap.off('moveend', this._onMainMapMoved, this);
        this._mainMap.off('move', this._onMainMapMoving, this);
        this._miniMap.off('moveend', this._onMiniMapMoved, this);

        this._miniMap.removeLayer(this._layer);
    },

    _addToggleButton: function() {
        this._toggleDisplayButton = this.options.toggleDisplay ? this._createButton('', this.hideText, 'leaflet-control-minimap-toggle-display', this._container, this._toggleDisplayButtonClicked, this) : undefined;
    },

    _createButton: function(html, title, className, container, fn, context) {
        var link = L.DomUtil.create('a', className, container);
        link.innerHTML = html;
        link.href = '#';
        link.title = title;

        var stop = L.DomEvent.stopPropagation;

        L.DomEvent.on(link, 'click', stop)
            .on(link, 'mousedown', stop)
            .on(link, 'dblclick', stop)
            .on(link, 'click', L.DomEvent.preventDefault)
            .on(link, 'click', fn, context);

        return link;
    },

    _toggleDisplayButtonClicked: function() {
        this._userToggledDisplay = true;
        if (!this._minimized) {
            this._minimize();
            this._toggleDisplayButton.title = this.showText;
        } else {
            this._restore();
            this._toggleDisplayButton.title = this.hideText;
        }
    },

    _setDisplay: function(minimize) {
        if (minimize != this._minimized) {
            if (!this._minimized) {
                this._minimize();
            } else {
                this._restore();
            }
        }
    },

    _minimize: function() {
        this._container.style.width = '0px';
        this._container.style.height = '0px';
        this._minimized = true;
    },

    _restore: function() {
        this._container.style.width = this.options.width + 'px';
        this._container.style.height = this.options.height + 'px';
        this._minimized = false;
    },

    _onMainMapMoved: function(e) {
        if (!this._miniMapMoving) {
			var zoom = this._decideZoom(true);
			if (zoom != 0) {
				//this._miniMap.setView(this._mainMap.getCenter(), this._decideZoom(true));
				//this._miniMap.setView(this._mainMap.getCenter());
			}
            this._mainMapMoving = true;

            this._setDisplay(this._decideMinimized());
        } else {
            this._miniMapMoving = false;
        }
		if (this.options.show_view) {
			this._aimingRect.setBounds(this._mainMap.getBounds());
		}
		this._locationCircle.setLatLng(this._mainMap.getCenter());
        
    },

    _onMainMapMoving: function(e) {
		if (this.options.show_view) {
			this._aimingRect.setBounds(this._mainMap.getBounds());
		}
		this._locationCircle.setLatLng(this._mainMap.getCenter());
    },

    _onMiniMapMoveStarted: function(e) {
        var lastAimingRect = this._aimingRect.getBounds();
        var sw = this._miniMap.latLngToContainerPoint(lastAimingRect.getSouthWest());
        var ne = this._miniMap.latLngToContainerPoint(lastAimingRect.getNorthEast());
        this._lastAimingRectPosition = {
            sw: sw,
            ne: ne
        };
    },

    _onMiniMapMoving: function(e) {
        if (!this._mainMapMoving && this._lastAimingRectPosition) {
            this._shadowRect.setBounds(new L.LatLngBounds(this._miniMap.containerPointToLatLng(this._lastAimingRectPosition.sw), this._miniMap.containerPointToLatLng(this._lastAimingRectPosition.ne)));
            this._shadowRect.setStyle({
                opacity: 1,
                fillOpacity: 0.3
            });
        }
    },

    _onMiniMapMoved: function(e) {
        if (!this._mainMapMoving) {
            this._miniMapMoving = true;
            this._mainMap.setView(this._miniMap.getCenter(), this._decideZoom(false));
            this._shadowRect.setStyle({
                opacity: 0,
                fillOpacity: 0
            });
        } else {
            this._mainMapMoving = false;
        }
    },

    _decideZoom: function(fromMaintoMini) {
        if (!this.options.zoomLevelFixed && this.options.zoomLevelFixed != 0) {
            if (fromMaintoMini) {
				return this._mainMap.getZoom() + this.options.zoomLevelOffset;
			} else {
				var currentDiff = this._miniMap.getZoom() - this._mainMap.getZoom();
				var proposedZoom = this._miniMap.getZoom() - this.options.zoomLevelOffset;
				var toRet;

				if (currentDiff > this.options.zoomLevelOffset && this._mainMap.getZoom() < this._miniMap.getMinZoom() - this.options.zoomLevelOffset) {
				    //This means the miniMap is zoomed out to the minimum zoom level and can't zoom any more.
				    if (this._miniMap.getZoom() > this._lastMiniMapZoom) {
				        //This means the user is trying to zoom in by using the minimap, zoom the main map.
				        toRet = this._mainMap.getZoom() + 1;
				        //Also we cheat and zoom the minimap out again to keep it visually consistent.
				        this._miniMap.setZoom(this._miniMap.getZoom() - 1);
				    } else {
				        //Either the user is trying to zoom out past the mini map's min zoom or has just panned using it, we can't tell the difference.
				        //Therefore, we ignore it!
				        toRet = this._mainMap.getZoom();
				    }
				} else {
				    //This is what happens in the majority of cases, and always if you configure the min levels + offset in a sane fashion.
				    toRet = proposedZoom;
				}
				this._lastMiniMapZoom = this._miniMap.getZoom();
				return toRet;
            }
        } else {
            if (fromMaintoMini) {
				return this.options.zoomLevelFixed;
			} else {
				return this._mainMap.getZoom();
			}
             
        }
    },

    _decideMinimized: function() {
        if (this._userToggledDisplay) {
            return this._minimized;
        }

        if (this.options.autoToggleDisplay) {
            if (this._mainMap.getBounds().contains(this._miniMap.getBounds())) {
                return true;
            }
            return false;
        }

        return this._minimized;
    }
});

L.Map.mergeOptions({
    miniMapControl: false
});

L.Map.addInitHook(function() {
    if (this.options.miniMapControl) {
        this.miniMapControl = (new L.Control.MiniMap()).addTo(this);
    }
});

L.control.minimap = function(options) {
    return new L.Control.MiniMap(options);
};
